--[[
	table 工具，暂时只用了个deepcopy
]]
local filelog = require "filelog"
local print = print
local tconcat = table.concat
local tinsert = table.insert
local srep = string.rep
local type = type
local pairs = pairs
local tostring = tostring
local next = next

local index = {}
local mt_defaultvalue = {__index = function (t)
	return t.__
end}

local mt_monitor = {
	__index = function (t, k)
		filelog.sys_obj("tabletool", "monitor", "*access to element "..tostring(k))
		return t[index][k]
	end,

	__newindex = function (t, k, v)
		filelog.sys_obj("tabletool", "monitor", "*update to element "..tostring(k).." to "..tostring(v))
		t[index][k] = v
	end
}


local TableTool = {}

--设置默认值表
function TableTool.set_default(t, defaultvalue)
	t__ = defaultvalue
	setmetatable(t, mt_defaultvalue)
end

--监控表的访问情况
function TableTool.track(t)
	local proxy = {}
	proxy[index] = t
	setmetatable(proxy, mt_monitor)
	return proxy
end

--创建只读表
function TableTool.create_readonlytable(t)
	local proxy = {}
	local mt = {
		__index = t,
		__newindex = function (t, k, v)
			error("attempt to update a read-only table", 2)
		end
	}

	setmetatable(proxy, mt)
	return proxy
end

--判断一张表是否为空
function TableTool.is_emptytable(t)
	if t == nil or type(t) ~= "table" then
		return false
	end
	return (_G.next( t ) == nil or TableTool.getn(t) == 0)
end

--取得hashtable的元素个数
function TableTool.getn(t)
	local count = 0
	for _, _ in pairs(t) do
		count = count + 1
	end
	return count
end

--将table转换为string
function TableTool.tostring(table)
	local cache = {  [table] = "." }
	local function _dump(t,space,name)
		local temp = {}
		for k,v in pairs(t) do
			local key = tostring(k)
			if cache[v] then
				tinsert(temp,"+" .. key .. " {" .. cache[v].."}")
			elseif type(v) == "table" then
				local new_key = name .. "." .. key
				cache[v] = new_key
				tinsert(temp,"+" .. key .. _dump(v,space .. (next(t,k) and "|" or " " ).. srep(" ",#key),new_key))
			else
				tinsert(temp,"+" .. key .. " [" .. tostring(v).."]")
			end
		end
		return tconcat(temp,"\n"..space)
	end
	return _dump(table, "","")
end

--深度copy table object
function TableTool.deepcopy(object)
	local lookup_table = {}
	local function _copy(object)
		if type(object) ~= "table" then
			return object
		elseif lookup_table[object] then
			return lookup_table[object]
		end	-- if
		local new_table = {}
		lookup_table[object] = new_table
		for index, value in pairs(object) do
			new_table[_copy(index)] = _copy(value)
		end	-- for
		return new_table
		--return setmetatable(new_table, _copy( getmetatable(object) ))
	end	-- function _copy
	return _copy(object)
end	-- function deepcopy

--打印table
function TableTool.print_r(root)
	local cache = {  [root] = "." }
	local function _dump(t,space,name)
		local temp = {}
		for k,v in pairs(t) do
			local key = tostring(k)
			if cache[v] then
				tinsert(temp,"+" .. key .. " {" .. cache[v].."}")
			elseif type(v) == "table" then
				local new_key = name .. "." .. key
				cache[v] = new_key
				tinsert(temp,"+" .. key .. _dump(v,space .. (next(t,k) and "|" or " " ).. srep(" ",#key),new_key))
			else
				tinsert(temp,"+" .. key .. " [" .. tostring(v).."]")
			end
		end
		return tconcat(temp,"\n"..space)
	end
	print(_dump(root, "",""))
end

--删除数组table中指定的元素值
 function TableTool.remove_item(list, item, removeall)
	 local rmcount = 0
	 for i = 1, #list do
		 if list[i - rmcount] == item then
			 table.remove(list, i - rmcount)
			 if removeall then
			 	rmcount = rmcount + 1
			 else
			 	break
			 end
		 end
	 end
 end

local function writetablecontent( file, obj, index, flag )
	-- body
	local szType = type(obj)
	filelog.sys_error("----szType----", szType)
	if szType == "number" then
		file:write(obj)
	elseif szType == "string" then
		file:write(string.format("%q", obj))
	elseif szType == "table" then
		--把table的内容格式化写入文件
		index = index + 1
		local spaces = ""
		for i=1,index do
			spaces = spaces .. " "
		end
		if flag == false then
			file:write(spaces .. "{\n")
		else
			file:write("{\n")
		end
		for i, v in pairs(obj) do
			if type(i) ~= "number" then
				file:write(spaces .. " ")
				file:write(i)
				file:write("=")
				writetablecontent(file, v, index, true)
			else
				writetablecontent(file, v, index, false)
			end
			if type(v) ~= "table" then
				file:write(", \n")
			end
		end
		if index > 1 then
			file:write(spaces .. "},\n")
		else
			file:write(spaces .. "}\n")
		end
	else
			filelog.sys_error("can't serialize a "..szType)
	end
	if index > 1 then
		index = index - 1
	end
end



function TableTool.savetablecontent(filename, obj)
	if filename == nil or obj == nil then return end
	local file = io.open(filename, "w+")
	if not file then return end
	local index = 0
	local flag = false
	file:write("return \n")
	writetablecontent(file, obj, index, flag)

	file:close()
end

function TableTool.keys(t)
	local keys = {}
	local i = 1
	for k, _ in pairs( t ) do
		keys[i] = k
		i = i + 1
	end
    return keys
end

--将table转化为string
--string再转化为table，使用TableTool.string2table
--
function TableTool.table2string(t)
    assert(type(t) == "table","only can convert table to string!")
    local str = "{"

    for k,v in pairs(t) do
        if type(k) == "number" then
            str = str .. "[" .. k .. "]="
        elseif string.sub(tostring(k),1,2) == "__" then
            v = nil
        else
            str = str .. k .. "="
        end

        if type(v) == "table" then
            str = str .. TableTool.table2string(v)
        elseif type(v) == "string" then
            str = str .. "\"" .. v .. "\""
        elseif type(v) == "boolean" then
            str = str .. ((v and "true") or "false")
        elseif type(v) == "function" then
            assert(false,"can't convert function to string!") 
        elseif type(v) == "userdata" then
            local mt = getmetatable(v)
            if mt ~= nil then
                str = str .. TableTool.table2string(mt)
            end
        elseif type(v) ~= "nil" then
            str = str .. v
        end

        if v ~= nil then
            str = str .. ","
        end
    end

    local metatable = getmetatable(t)  
    if metatable ~= nil and type(metatable.__index) == "table" then  
        str = str .. "__mt=" .. TableTool.table2string(metatable.__index)
    else
        str = string.sub(str,0,#str-1)
	end
    str = str .. "}"

    return str
end

function string.trim(input)
    input = string.gsub(input, "^[ \t\n\r]+", "")
    return string.gsub(input, "[ \t\n\r]+$", "")
end

--将string转化为table
--string是由TableTool.table2string转化而来
--
function TableTool.string2table(str)
    assert("string" == type(str),"only can convert a string!")
    str = string.trim(str)
    local head = string.sub(str,1,1)
    local tail = string.sub(str,-1)
    assert(head == '{' and tail == '}',"it's not a table string!")

    local t = assert(load("return" .. str),"table format error!")()
    if t.__mt and type(t.__mt) == "table" then
        setmetatable(t,{__index = t.__mt})
        t.__mt = nil
    end

    return t
end

return TableTool
